﻿using CPPEI.Coolzon.UI.Script;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CPPEI.Coolzon.UI
{
    public class ScriptEngine
    {
        private Dictionary<string, object> _addedObjectList = new Dictionary<string, object>();
        private List<string> _addedCodeList = new List<string>();

        public bool IsUsable = true;

        public string Name { get; private set; }

        private Microsoft.ClearScript.ScriptEngine _innerSE;

        private ScriptEngine(string name)
        {
            this.Name = name;
            _innerSE = new Microsoft.ClearScript.V8.V8ScriptEngine();
        }

        public static ScriptEngine Create(string name)
        {
            return new ScriptEngine(name);
        }

        public void Reset()
        {
            //try
            //{
            //    _addedObjectList.Clear();
            //    _addedCodeList.Clear();
            //    Noesis.Javascript.JavascriptContext.Collect();
            //}
            //catch (Exception ex)
            //{
            //    CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG,
            //        string.Format("Engine:{0},reset出错ex:{1}", this.Name, ex));
            //}
        }

        public void AddCode(string code)
        {
            _addedCodeList.Add(code);
        }

        /// <summary>
        /// 往引擎中添加对象
        /// </summary>
        /// <param name="name"></param>
        /// <param name="obj"></param>
        public void AddObject(string name, object obj)
        {
            if (obj == null)
            {
                CPPEI.Coolzon.Common.Logger.WarningToTag(Library.LogScriptTAG, "添加对象失败，对象为空");
                return;
            }
            if (_addedObjectList.ContainsKey(name))
            {
                _addedObjectList[name] = obj;
            }
            else
            {
                _addedObjectList.Add(name, obj);
            }

            try
            {
                _innerSE.AddHostObject(name, obj);
            }
            catch (Exception ex)
            {
                CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0},AddObject:{1}出错,ex:{2}", this.Name, name, ex));
                return;
            }
        }

        /// <summary>
        /// 向脚本引擎中添加脚本文件
        /// </summary>
        /// <param name="filePath">脚本文件</param>
        public void AddFile(string filePath)
        {
            try
            {
                _addedCodeList.Add(File.ReadAllText(filePath));
                _innerSE.Execute(_addedCodeList.Last());
            }
            catch (Exception ex)
            {
                CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0},读取脚本文件:{1}出错,ex:{2}", this.Name, filePath, ex));
            }
        }

        /// <summary>
        /// 执行一个表达式，返回表达式计算的结果
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public object RunExpression(string expression)
        {
            object ret = null;
            try
            {
                ret= _innerSE.Evaluate(expression);
            }
            catch (Exception ex)
            {
                CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0}执行脚本1:{1}出错,ex:{2}", this.Name, expression, ex));
            }
            //System.Windows.Application.Current.Dispatcher.Invoke(() =>
            //{
            //    try
            //    {
            //        using (Noesis.Javascript.JavascriptContext jc = new Noesis.Javascript.JavascriptContext())
            //        {
            //            foreach (var item in _addedObjectList)
            //            {
            //                jc.SetParameter(item.Key, item.Value, Noesis.Javascript.SetParameterOptions.None);
            //            }
            //            foreach (var code in _addedCodeList)
            //            {
            //                jc.Run(code);
            //            }
            //            ret = jc.Run(expression);
            //        }
            //    }
            //    catch (Exception ex)
            //    {
            //        CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0}执行脚本1:{1}出错,ex:{2}", this.Name, expression, ex));
            //    }
            //});
            return ret;
        }

        /// <summary>
        /// 运行数据表达式
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="dataSeries"></param>
        /// <param name="dataItem"></param>
        /// <returns></returns>
        [Obsolete("以后应该要去掉此方法，换成事件来处理控件的可见性")]
        public bool RunDataExpressionToBoolean(string expression, object dataSeries, object dataItem)
        {
            bool ret = false;

            //System.Windows.Application.Current.Dispatcher.Invoke(() =>
            //{
            //    try
            //    {
            //        using (Noesis.Javascript.JavascriptContext jc = new Noesis.Javascript.JavascriptContext())
            //        {
            //            foreach (var item in _addedObjectList)
            //            {
            //                jc.SetParameter(item.Key, item.Value, Noesis.Javascript.SetParameterOptions.None);
            //            }
            //            foreach (var code in _addedCodeList)
            //            {
            //                jc.Run(code);
            //            }
            //            jc.SetParameter("dataSeries", dataSeries, Noesis.Javascript.SetParameterOptions.None);
            //            jc.SetParameter("data", dataItem, Noesis.Javascript.SetParameterOptions.None);
            //            object retValueObj = jc.Run(expression);
            //            CPPEI.Coolzon.Common.Logger.DebugToTag(Library.LogScriptTAG, string.Format("Engine:{0},run expression: {1}成功!", this.Name, expression));

            //            if (retValueObj != null)
            //            {
            //                ret = Convert.ToBoolean(retValueObj);
            //            }
            //        }
            //    }
            //    catch (Exception ex)
            //    {
            //        CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0}执行脚本2:{1}出错,ex:{2}", this.Name, expression, ex));
            //    }
            //});
            return ret;
        }

        public bool RunExpressionToBoolean(string expression)
        {
            bool ret = false;
            //System.Windows.Application.Current.Dispatcher.Invoke(() =>
            //{
            //    try
            //    {
            //        using (Noesis.Javascript.JavascriptContext jc = new Noesis.Javascript.JavascriptContext())
            //        {
            //            foreach (var item in _addedObjectList)
            //            {
            //                jc.SetParameter(item.Key, item.Value, Noesis.Javascript.SetParameterOptions.None);
            //            }
            //            foreach (var code in _addedCodeList)
            //            {
            //                jc.Run(code);
            //            }
            //            object result = jc.Run(expression);
            //            if (result != null)
            //            {
            //                ret = (bool)result;
            //            }
            //        }
            //    }
            //    catch (Exception ex)
            //    {
            //        CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0}执行脚本3:{1}出错,ex:{2}", this.Name, expression, ex));
            //    }
            //});
            return ret;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="func"></param>
        /// <param name="parameters"></param>
        public void Run(string func, params object[] parameters)
        {
            try
            {
                _innerSE.Invoke(func, parameters);
            }
            catch (Exception ex)
            {
                CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0},run {1}出错!", this.Name, func), ex);
            }
            //System.Windows.Application.Current.Dispatcher.Invoke(() =>
            //{
            //    try
            //    {
            //        using (Noesis.Javascript.JavascriptContext jc = new Noesis.Javascript.JavascriptContext())
            //        {
            //            foreach (var item in _addedObjectList)
            //            {
            //                jc.SetParameter(item.Key, item.Value, Noesis.Javascript.SetParameterOptions.None);
            //            }
            //            foreach (var code in _addedCodeList)
            //            {
            //                jc.Run(code);
            //            }
            //            StringBuilder expression = new StringBuilder(func);
            //            expression.Append("(");
            //            for (int index = 0; index < parameters.Length; index++)
            //            {
            //                jc.SetParameter(string.Format("p_cz_p{0}", index), parameters[index], Noesis.Javascript.SetParameterOptions.None);

            //                if (index > 0)
            //                {
            //                    expression.Append(string.Format(",p_cz_p{0}", index));
            //                }
            //                else
            //                {
            //                    expression.Append(string.Format("p_cz_p{0}", index));
            //                }
            //            }
            //            expression.Append(");");
            //            jc.Run(expression.ToString());
            //            CPPEI.Coolzon.Common.Logger.DebugToTag(Library.LogScriptTAG, string.Format("Engine:{0},run {1}成功!", this.Name, func));
            //        }
            //    }
            //    catch (Exception ex)
            //    {
            //        CPPEI.Coolzon.Common.Logger.ErrorToTag(Library.LogScriptTAG, string.Format("Engine:{0},run {1}出错!", this.Name, func), ex);
            //    }
            //});
        }

        public void Close()
        {
            Reset();
            _innerSE.Dispose();
        }

        public object GetObject(string name)
        {
            return _addedObjectList[name];
        }
    }
}
